﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PetaPoco;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching;
using PmSoft.DBContext;
using PmSoft.Exceptions;
using PmSoft.Repositories;

namespace Modules.System.Role
{
    [UseDI(ServiceLifetime.Scoped)]
    public class SysRoleMenuRepository : Repository<SysRoleMenu, DefaultDbContext>
    {
        private readonly ILogger logger;
        private static readonly SysRoleMenuComparer comparer = new SysRoleMenuComparer();

        public SysRoleMenuRepository(DefaultDbContext dbContext, IApplicationContext applicationContext, ILogger<SysRoleMenuRepository> logger)
            : base(dbContext, applicationContext)
        {
            this.logger = logger;
        }

        /// <summary>
        /// 创建或更新角色与菜单关系数据
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="inRoleMenus"></param>
        /// <exception cref="BusinessException"></exception>
        public void CreateOrUpdate(int roleId, string roleCode, IEnumerable<SysRoleMenu> inRoleMenus)
        {
            try
            {
                DbContext.BeginTransaction();
                var dbRoleMenus = DbContext.Fetch<SysRoleMenu>("WHERE role_id=@0", roleId);

                //删除
                var itemsToDelete = dbRoleMenus.Except(inRoleMenus, comparer).ToList();
                foreach (var item in itemsToDelete)
                {
                    Delete(item);
                }

                ////更新
                //var itemsToUpdate = dbRoleMenus.Intersect(inRoleMenus, comparer).ToList();
                //foreach (var item in itemsToUpdate)
                //{
                //}

                //新增
                var itemsToAdd = inRoleMenus.Except(dbRoleMenus, comparer).ToList();
                foreach (var item in itemsToAdd)
                {
                    item.RoleCode = roleCode;
                    Insert(item);
                }
                DbContext.CompleteTransaction();
            }
            catch (Exception ex)
            {
                DbContext.AbortTransaction();
                string message = "角色菜单关系数据事务执行失败";
                logger.LogError(ex, message);
                throw new BusinessException(message);
            }
        }

        /// <summary>
        /// 根据角色ID获取关系集合
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public IEnumerable<SysRoleMenu> GetRoleMenuByRoleId(int roleId)
        {
            int areaVersion = EntityCacheService.GetAreaVersion("RoleId", roleId);
            return GetTopEntities(1000, CachingExpirationType.ObjectCollection, () =>
            {
                return $"RoleMenuByUserId:{roleId}:{areaVersion}";
            }, () =>
            {
                Sql sql = Sql.Builder
                .Select("id")
                .From("sys_role_menu")
                .Where("role_id=@0", roleId);
                return sql;
            });
        }

        /// <summary>
        /// 根据多个角色集合获取菜单集合
        /// </summary>
        /// <param name="roleIds"></param>
        /// <returns></returns>
        public IEnumerable<SysRoleMenu> GetMenuIdsByRoleIds(IEnumerable<int> roleIds)
        {
            if (roleIds == null || roleIds.Count() == 0)
                return Enumerable.Empty<SysRoleMenu>();
 
            return GetAllRoleMenus().Where(m => roleIds.Contains(m.RoleId));
            //var globalVersion = EntityCacheService.GetGlobalVersion();
            //return GetTopEntities(1000, CachingExpirationType.RelativelyStable, () =>
            //{
            //    return $"MenuIdsByRoleIds:{string.Join("-", roleIds)}:{globalVersion}";
            //}, () =>
            //{
            //    Sql sql = Sql.Builder
            //        .Select("menu_id")
            //        .From("sys_role_menu")
            //        .Where("role_id IN(@0)", roleIds);
            //    return sql;
            //});
        }

        /// <summary>
        /// 根据菜单ID获取关系集合
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public IEnumerable<SysRoleMenu> GetRoleMenuByMenuId(int menuId)
        {
            int areaVersion = EntityCacheService.GetAreaVersion("MenuId", menuId);
            return GetTopEntities(1000, CachingExpirationType.ObjectCollection, () =>
            {
                return $"RoleMenuByMenuId:{menuId}:{areaVersion}";
            }, () =>
            {
                Sql sql = Sql.Builder
                .Select("id")
                .From("sys_role_menu")
                .Where("menu_id=@0", menuId);
                return sql;
            });
        }

        public IEnumerable<SysRoleMenu> GetAllRoleMenus()
        {
            var globalVersion = EntityCacheService.GetGlobalVersion();
            return GetTopEntities(1000, CachingExpirationType.RelativelyStable, () =>
              {
                  return $"AllRoleMenus:{globalVersion}";
              }, () =>
              {

                  Sql sql = Sql.Builder
                      .Select("sys_role_menu.id")
                      .From("sys_role_menu")
                      .InnerJoin("sys_role").On("sys_role.role_id=sys_role_menu.role_id AND sys_role.status = 1 AND sys_role.is_deleted = 0");
                  return sql;
              });
            //string sql = string.Format("SELECT a.role_id, a.menu_id , a.role_code FROM sys_role_menu AS a LEFT JOIN sys_role AS b ON a.role_id = b.role_id AND b.`status` = 1 AND b.is_deleted = 0 GROUP BY a.role_id, a.menu_id, a.role_code");
            //  return DbContext.Query<SysRoleMenu>(sql);
        }
    }
}